package yb.ecp.fast.user.web;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.user.infra.BasicController;
import yb.ecp.fast.user.service.HanyunLoginUserService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@RefreshScope
@RestController
@RequestMapping("/hanyun")
@Api(tags = "对接汉云oss")
public class HanyunController extends BasicController {

    @Value("${hanyun.oauth2.client_id}")
    private String clientId;

    @Value("${hanyun.oauth2.client_secret}")
    private String clientSecret;

    @Value("${hanyun.oss-token-url}")
    private String ossGetTokenUrl;

    @Value("${hanyun.oss-user-url}")
    private String ossUserInfoUrl;

    @Value("${hanyun.oss-logout-url:/logout}")
    private String ossLogoutUrl;

    @Value("${hanyun.main-front-url}")
    private String mainFrontUrl;
    @Value("${hanyun.oauth2.oss-redirect-url}")
    private String ossDirectUrl;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private HanyunLoginUserService hanyunLoginUserService;

    @RequestMapping(value = "/ossLogin", method = RequestMethod.GET)
    public ActionResult<String> ossLogin(HttpServletRequest req) throws IOException {
        String code = req.getParameter("code");
        Object resultBody = getCodeToken(code, ossDirectUrl);
        if (!(resultBody instanceof LinkedHashMap)) {
            throw new RuntimeException("OSS登陆失败");
        }
        Object accessToken = ((LinkedHashMap<?, ?>) resultBody).get("access_token");
        if (accessToken == null) {
            throw new RuntimeException("OSS登陆失败,access_token获取失败");
        }
        Map<String, String> user = getUserInfo(String.valueOf(accessToken));
        if (MapUtil.isEmpty(user) || !user.containsKey("userId")) {
            throw new RuntimeException("OSS登陆失败,根据accessToken获取用户信息获取失败");
        }
        return actionResult(user.get("userId"));
    }

    @RequestMapping(value = "/loginByCode", method = RequestMethod.GET)
    public void loginByCode(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String code = req.getParameter("code");
        Object resultBody = getCodeToken(code, ossDirectUrl);
        if (!(resultBody instanceof LinkedHashMap)) {
            throw new RuntimeException("OSS登陆失败");
        }
        Object accessToken = ((LinkedHashMap<?, ?>) resultBody).get("access_token");
        if (accessToken == null) {
            resp.sendRedirect(mainFrontUrl + "?" + "errMsg=OSS登陆失败,access_token获取失败");
        }
        resp.sendRedirect(mainFrontUrl + "?" + "accessToken" + "=" + accessToken);
    }

    @RequestMapping(value = "/loginByOssAccessToken", method = RequestMethod.GET)
    public ActionResult<String> loginByOssAccessToken(@RequestParam(value = "accessToken", required = false) String accessToken) throws IOException {
        Map<String, String> user = getUserInfo(String.valueOf(accessToken));
        if (MapUtil.isEmpty(user) || !user.containsKey("userId")) {
            throw new RuntimeException("OSS登陆失败,根据accessToken获取用户信息获取失败");
        }
        return actionResult(user.get("userId"));
    }

    @RequestMapping(value = "/logoutOss", method = RequestMethod.GET)
    @ResponseBody
    public Object logoutOss(String token) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.set("X-Access-Token", token);
        headers.set("Authorization", "bearer " + token);
        HttpEntity entity = new HttpEntity(headers);
        ResponseEntity<JSONObject> jsonObject = restTemplate.exchange(ossLogoutUrl, HttpMethod.GET, entity, JSONObject.class);
        return jsonObject.getBody();
    }


    public Map<String, String> getUserInfo(String accessToken) {
        try {
            StringBuilder stringBuilder = new StringBuilder(ossUserInfoUrl);
            stringBuilder.append("?client_id=").append(clientId).append("&access_token=").append(accessToken);
            log.info("getUserInfo:  {}", stringBuilder);
            HttpHeaders headers = new HttpHeaders();
            headers.set("Authorization", "Bearer " + accessToken);
            HttpEntity entity = new HttpEntity(headers);
            ResponseEntity<JSONObject> jsonObject = restTemplate.exchange(stringBuilder.toString(), HttpMethod.GET, entity, JSONObject.class);
            if (null == jsonObject || !ObjectUtils.isEmpty(jsonObject.getBody().getString("error"))) {
                throw new RuntimeException("OSS登陆失败");
            }
            return hanyunLoginUserService.loginCheck(jsonObject.getBody(), accessToken);
        } catch (Exception e) {
            log.error("", e);
            throw new RuntimeException(e.getMessage());
        }
    }

    public Object getCodeToken(String code, String redirectUri) {
        StringBuilder tokenUrlBuffer = new StringBuilder(ossGetTokenUrl);
        tokenUrlBuffer.append("?grant_type=authorization_code&client_id=").append(clientId).append("&client_secret=")
                .append(clientSecret).append("&code=").append(code);
        if (!ObjectUtils.isEmpty(redirectUri)) {
            tokenUrlBuffer.append("&redirect_uri=").append(redirectUri);
        }
        log.info("token_url:" + tokenUrlBuffer);
        ResponseEntity<Object> result = restTemplate.postForEntity(tokenUrlBuffer.toString(), null, Object.class);
        return result.getBody();
    }


}
